;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Copyright 2021 fanguangping
; 
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
; 
;     http://www.apache.org/licenses/LICENSE-2.0
; 
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

#lang racket

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Utilities
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(provide (all-defined-out))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: make counter
; Input:
; Output: counter function
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (make-counter)
  (define counter 0)
  (lambda ()
    (set! counter (+ counter 1))
    counter))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Message generator
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define msg-gen (make-counter))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; State generator
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define state-gen (make-counter))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: make empty list
; Input:
;   size -> size of empties
; Output: empty list
; Example:
;   (make-empties 0) => '()
;   (make-empties 1) => '(())
;   (make-empties 2) => '(() ())
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (make-empties size)
  (if (= size 0) (list)
      (append (list '()) (make-empties (- size 1)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: make enumeration
; Input:
;   start -> the start number
;   end   -> the end number
; Output: enumeration list
; Example:
;   (make-enumeration 1 1) => '(1)
;   (make-enumeration 1 3) => '(1 2 3)
;   (make-enumeration 1 0) => '()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (make-enumeration start end)
  (if (> start end) '()
      (if (= start end) (list start)
          (append (list start) (make-enumeration (+ start 1) end)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: make association list
; Input:
;   klist -> key list
;   vlist -> value list
; Output: association list made by klist and vlist
; Example:
;   (make-alist '(1 2 3) '(a v x)) => '((1 . a) (2 . v) (3 . x))
;   (make-alist '(1 2) '(a v x))   => '((1 . a) (2 . v))
;   (make-alist '(1 2 3) '(a v))   => '((1 . a) (2 . v))
;   (make-alist '() '())           => '()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (make-alist klist vlist)
  (if (or (null? klist) (null? vlist)) '()
      (append (list (cons (car klist) (car vlist))) (make-alist (cdr klist) (cdr vlist)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: make associated enumeration list
; Input:
;   vlist -> value list
; Output: association enumeration list made by vlist
; Example:
;   (make-enumeration-list '(a v x)) => '((1 . a) (2 . v) (3 . x))
;   (make-enumeration-list '())      => '()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (make-enumeration-list vlist)
  (make-alist (make-enumeration 1 (length vlist)) vlist))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: split list by given element
; Input:
;   lst -> list to be splitted
;   x   -> the element
; Output: list of splitted list
; Example:
;   (split-by '(a b c x d x e x f) 'x) => '((a b c) (d) (e) (f))
;   (split-by '(x) 'x)                 => '(() ())
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (split-by lst x)
  (foldr (lambda (element next)
           (if (eqv? element x)
               (cons empty next)
               (cons (cons element (car next)) (cdr next))))
         (list empty) lst))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: produce list where inserted list b to list a one by one
; Input:
;   a -> list a
;   b -> list b
; Output: list produced
; Example:
;   (interleave '(1 2 3 4 5) '(a b c)) => '(1 a 2 b 3 c 4 5)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (interleave a b)
  (if (null? a)
      b
      (cons (car a)
            (interleave b (cdr a)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: produce list where inserted element to each gap of nodes
; Input:
;   element -> element
;   nodes   -> nodes
; Output: list produced
; Example:
;   (insert-between '(a b c) 'x) => '(a x b x c)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (insert-between nodes element)
  (if (empty? (cdr nodes))
      (list (car nodes))
      (cons (car nodes)
            (cons element (insert-between (cdr nodes) element)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: read lines from port
; Input:
;   port -> port
; Output: list of strings separated by newline
; Example:
;   (read-lines (open-input-string "a\nbb\ncd\ne")) => '("a" "bb" "cd" "e")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (read-lines port)
  (define (next-line-it port)
    (let ((line (read-line port 'any)))
      (if (eof-object? line)
          '()
          (append (list line)
                  (next-line-it port)))))
  (let ((lines (next-line-it port)))
    (close-input-port port)
    lines))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: not null predicate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (not-null? t) (not (null? t)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: not equal predicate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (not-equal? a b) (not (equal? a b)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: non blank string predicate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (non-blank-string? t) (non-empty-string? (string-trim t)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: flatmap
; Input:
;   f   -> mapping function
;   lst -> list
; Output: list mapped
; Example:
;   (flatmap (lambda (t) t) '((a b c) (e f) (z h))) => '(a b c e f z h)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (flatmap f lst)
  (apply append (map f lst)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: safe function call
; Example:
;   (safe car (cons 'a 'b)) => 'a
;   (safe car '()) => '()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (safe f t)
  (if (null? t) t
      (f t)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: cartesian product of lists
; Example:
;   (cartesian-product-list '((4 5) (d e f) (#t))) => '((4 d #t) (4 e #t) (4 f #t) (5 d #t) (5 e #t) (5 f #t))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (cartesian-product-list lists)
  (foldr (lambda (xs ys)
           (append-map (lambda (x)
                         (map (lambda (y)
                                (cons x y))
                              ys))
                       xs))
         '(())
         lists))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: get value of alist by key
; Example:
;   (assoc-value '((a . 123) (b . 456)) 'a)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (assoc-value alist key)
  (cdr (assoc key alist)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: get replaced string by alist
; Example:
;   (string-replace-by-alist "aebea" '(("a" . "123") ("b" . "456"))) => "123e456e123"
; Warning: one should not include another
;   (string-replace-by-alist "<integer>\\/<uinteger>" '(("integer" . "1") ("uinteger" . "2"))) => "<1>\\/<u1>"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (string-replace-by-alist str alist)
  (if (null? alist) str
      (string-replace-by-alist (string-replace str (caar alist) (cdar alist)) (cdr alist))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: every element in collection feeds the predicate
; Input:
;   predicate -> predicate
;   collection -> collection
; Output: feeds or not feeds
; Example:
;   (every? char? (list #\a #\b #\c)) => #t
;   (every? char? (list "a" #\b #\c)) => #f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (every? predicate collection)
  (foldr (lambda (x y) (and x y)) #t (map predicate collection)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: all elements in collection feeds the predicate
; Input:
;   predicate -> predicate
;   collection -> collection
; Output: feeds or not feeds
; Example:
;   (all? char? (list #\a #\b #\c)) => #t
;   (all? char? (list "a" #\b #\c)) => #f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define all? every?)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: some elements in collection feeds the predicate
; Input:
;   predicate -> predicate
;   collection -> collection
; Output: feeds or not feeds
; Example:
;   (some? char? (list #\a #\b #\c)) => #f
;   (some? char? (list "a" #\b #\c)) => #t
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (some? predicate collection)
  (not (every? predicate collection)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: any element in collection feeds the predicate
; Input:
;   predicate -> predicate
;   collection -> collection
; Output: feeds or not feeds
; Example:
;   (any? char? (list "a" #\b #\c)) => #t
;   (any? char? (list "a" "b" "c")) => #f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (any? predicate collection)
  (foldr (lambda (x y) (or x y)) #f (map predicate collection)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: none of elements in collection feeds the predicate
; Input:
;   predicate -> predicate
;   collection -> collection
; Output: feeds or not feeds
; Example:
;   (none? char? (list "a" #\b #\c)) => #f
;   (none? char? (list "a" "b" "c")) => #t
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (none? predicate collection)
  (not (any? predicate collection)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: concatenate collections
; Input:
;   collections -> collections
; Output: collection concatenated
; Example:
;   (concat '(1 2 3) '(4 5 6) '(7 8 9)) => '(1 2 3 4 5 6 7 8 9)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (concat . collections)
  (foldr append '() collections))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: mutable list to immutable list
; Input:
;   lst -> the list mutable
; Output: immutable list transformed
; Example:
;   (mlist->list (mcons 1 (mcons 2 (mcons 3 '())))) => '(1 2 3)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (mlist->list lst)
  (if (null? lst) '()
      (cons (mcar lst) (mlist->list (mcdr lst)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: immutable list to mutable list
; Input:
;   lst -> the list immutable
; Output: mutable list transformed
; Example:
;   (list->mlist '(1 2 3)) => (mcons 1 (mcons 2 (mcons 3 '())))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (list->mlist lst)
  (if (null? lst) '()
      (mcons (car lst) (list->mlist (cdr lst)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: mutable map
; Input:
;   lst -> the list mutable
; Output: mutable map results
; Example:
;   (mmap - (mcons 1 (mcons 2 (mcons 3 '())))) => '(-1 -2 -3)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (mmap f lst)
  (if (null? lst) '()
      (mcons (f (mcar lst)) (mmap f (mcdr lst)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: mutable filter
; Input:
;   pred -> the predicate
;   lst -> the list mutable
; Output: mutable filter results
; Example:
;   (mfilter even? (mcons 1 (mcons 2 (mcons 3 '())))) => (mcons 2 '())
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (mfilter pred lst)
  (cond
    ((null? lst)
     null)
    ((pred (mcar lst))
     (mcons (mcar lst) (mfilter pred (mcdr lst))))
    (else
     (mfilter pred (mcdr lst)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: Split text where matched by regex, and then transform each item by function(split or match) to form a list
; Input:
;   text -> text to process
;   re -> regex
;   split-f -> split function
;   match-f -> match function
; Output: list produced
; Example:
;   (intermatch "MAKE-%className% self %properties%" #rx"%[^%]*%" identity identity) => '("MAKE-" "%className%" " self " "%properties%")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (intermatch text re split-f match-f)
  (interleave
   (map split-f (regexp-split re text))
   (map match-f (regexp-match* re text))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: Split text into alist and expand alist where matched by regexes, and then transform each item by function(split or match)
; Input:
;   text-list -> text list to process
;   re-list -> regex list to split
;   split-f -> split function
;   match-f-list -> match function list
;   expand-p -> expand predicate
; Output: list produced
; Example:
;
; (define (slice text)
;   (multimatch
;    (list (cons text "text-node"))
;    (list #px"[A-Z]+\\[[^\\]]*\\]"
;          #px"\\{[a-z][a-z|0-9|-]+\\}"
;          #px"\\\\\\{|\\\\\\}")
;    (lambda (t) (cons t "text-node"))
;    (list (lambda (t) (cons (token-escape t) "macro-node"))
;          (lambda (t) (cons (token-escape t) "argument-node"))
;          (lambda (t) (cons (token-escape t) "text-node")))
;    (lambda (t) (eq? (cdr t) "text-node"))
;    ))
; (slice "{function} > \\{(EXTRACT[{name}] TARGET[{function}])\\}")
; 
; =>
; 
; '(("" . "text-node")
;   ("{function}" . "argument-node")
;   (" > " . "text-node")
;   ("{" . "text-node")
;   ("(" . "text-node")
;   ("EXTRACT[{name}]" . "macro-node")
;   (" " . "text-node")
;   ("TARGET[{function}]" . "macro-node")
;   (")" . "text-node")
;   ("}" . "text-node")
;   ("" . "text-node"))
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (multimatch text-list re-list split-f match-f-list expand-p)
  (if (null? re-list) text-list
      (multimatch
       (flatmap
        (lambda (t)
          (if (expand-p t)
              (intermatch (if (pair? t) (car t) t) (car re-list) split-f (car match-f-list))
              (cons t '())))
        text-list)
       (cdr re-list)
       split-f
       (cdr match-f-list)
       expand-p)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: char followed by backslash to produce escape char
; Input:
;   c -> char
; Output: the escape char
; Example:
;   (escape #\n) => #\newline
;   (escape #\a) => #f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (escape c)
  (let ((t (assoc c '((#\\ . #\\) (#\t . #\tab) (#\n . #\newline) (#\r . #\return) (#\" . #\")))))
    (if t (cdr t) #f)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: escape token string
; Input:
;   t -> the token
; Output: the escaped token string
; Example:
;   (token-escape "\\\\abc") => "\\abc"
;   (token-escape "\\\"") => "\""
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (token-escape t)
  (if (string-prefix? t "\\")
      (substring t 1)
      t))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: strip and extract string between left and right
; Input:
;   str -> the string to strip
;   left -> left side
;   right -> right side
; Output: the string extracted
; Example:
;   (string-strip "( a b c )" "(" ")") => "a b c"
;   (string-strip "[abc]" "[" "]") => "abc"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (string-strip str left right)
  (string-trim (string-trim (string-trim str left #:left? #t) right #:right? #t)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: chain map functions
; Example:
;   (map-chain (lambda (t) (string-append t "abc")) (lambda (t) (format "~a" t)) '(1 2 3)) => '("1abc" "2abc" "3abc")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (map-chain . args)
  (define (map-chain-inner args)
    (cond ((null? args) '())
          ((= (length args) 1) (first args))
          (else (map (first args) (map-chain-inner (rest args))))))
  (map-chain-inner args))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Description: padding tail of list, make it easier to process sometimes
; Example:
;   (list-padding-tail (list 1 2 3) 4) => '(1 2 3 ())
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (list-padding-tail lst size)
  (define len (length lst))
  (if (>= len size) lst
      (append lst (make-empties (- size len)))))

